/*
 * SiFiSy - A File System Simulator
 * Copyright (C) 2010  SevenSoft
 *
 * This file is part of SiFiSy.
 *
 * SiFiSy is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * SiFiSy is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with SiFiSy.  If not, see <http://www.gnu.org/licenses/>.
 */

package sifisy.newgui;

import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
import javax.swing.border.TitledBorder;
import java.util.Vector;
import javax.swing.filechooser.FileNameExtensionFilter;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.DefaultTreeModel;
import sifisy.core.Model;

/**
 * @author Giuseppe Biolo
 * @version %I%, %G%
 * @createData 12/05/2010
 */
public class MainWidget extends JFrame {
    public static final int FILEFILTER_PDF = 0;
    public static final int FILEFILTER_SIMULATION = 1;
    public static final int FILEFILTER_PROJECT = 2;
    public static final int FILEFILTER_PNG = 3;
    public static final int FILEFILTER_ALL = 4;

    private Vector<SimulationPanel> simulations;
    private static Vector<String> simulationsList;
    private static Vector<String> projectsList;
    private static JTabbedPane tabbedPane;
    private static JTree treeView;
    private static JFrame mainWidgetFrame;
    private JMenuBar fileMenu;
    private JMenu file;
    //private JMenu simulation;
    //private JMenu project;
    private JMenu help;
    private JMenuItem newSimulation;
    private JMenuItem newProject;
    private JMenuItem wizard;
    private JMenuItem open;
    private JMenuItem closeSimulation;
    private JMenuItem closeProject;
    private JMenuItem save;
//    private JMenuItem saveAs;
    private JMenuItem preferences;
    private JMenuItem exit;
  //  private JMenuItem startSimulation;
  //  private JMenuItem parameters;
//    private JMenuItem startComparison;
    private JMenuItem helpWizard;
    private JMenuItem about;
    private JButton newSimulationButton;
    private JButton newProjectButton;
    private JButton openButton;
    private JButton saveButton;
//    private JButton saveAsButton;
    private JButton helpButton;
  //  private JList nowOpen;
    private JLabel messages;

    private static DefaultMutableTreeNode rootNode;

    static {
        tabbedPane = new JTabbedPane();
        // tabs scrolled in a single line (not multiline)
        tabbedPane.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
        treeView = new JTree();
        treeView.setShowsRootHandles(true);
        simulationsList = new Vector<String>();
        projectsList = new Vector<String>();
    }

    // tabbedPane and treeView are static members of class MainWidget so
    // they can be accessed using MainWidget.getTabbedPane() and
    // MainWidget.getTreeView()
    // (doesn't need a reference to a MainWidget object)
    public static JTabbedPane getTabbedPane() {
        return tabbedPane;
    }

    public static JTree getTreeView() {
        return treeView;
    }

    public static JFrame getMainWidgetFrame() {
        return mainWidgetFrame;
    }

    private void initComponents() {
        // Initialization of environment variables
        fileMenu = new JMenuBar();
        file = new JMenu(Model.translate("file"));
//        simulation = new JMenu(Model.translate("simulation"));
  //      project = new JMenu(Model.translate("project"));
        help = new JMenu(Model.translate("help"));
        newSimulation = new JMenuItem(Model.translate("newSimulation"));
        newSimulation.setIcon(new ImageIcon(getClass().getResource("icons/small/newSimulation.png")));
        newProject = new JMenuItem(Model.translate("newProject"));
        newProject.setIcon(new ImageIcon(getClass().getResource("icons/small/newProject.png")));
        wizard = new JMenuItem(Model.translate("wizard"));
        wizard.setIcon(new ImageIcon(getClass().getResource("icons/small/wizard.png")));
        open = new JMenuItem(Model.translate("open"));
        open.setIcon(new ImageIcon(getClass().getResource("icons/small/open.png")));
        closeSimulation = new JMenuItem(Model.translate("closeSimulation"));
        closeProject = new JMenuItem(Model.translate("closeProject"));
        save = new JMenuItem(Model.translate("save"));
        save.setIcon(new ImageIcon(getClass().getResource("icons/small/save.png")));
//        saveAs = new JMenuItem(Model.translate("saveAs"));
//        saveAs.setIcon(new ImageIcon(getClass().getResource("icons/small/saveAs.png")));
        preferences = new JMenuItem(Model.translate("preferences"));
        preferences.setIcon(new ImageIcon(getClass().getResource("icons/small/preferences.png")));
        exit = new JMenuItem(Model.translate("exit"));
        exit.setIcon(new ImageIcon(getClass().getResource("icons/small/exit.png")));
//        startSimulation = new JMenuItem(Model.translate("startSimulation"));
//        startSimulation.setIcon(new ImageIcon(getClass().getResource("icons/small/startSimulation.png")));
//        parameters = new JMenuItem(Model.translate("parameters"));
//        startComparison = new JMenuItem(Model.translate("startComparison"));
//        startComparison.setIcon(new ImageIcon(getClass().getResource("icons/small/startProject.png")));
        helpWizard = new JMenuItem(Model.translate("helpWizard"));
        about = new JMenuItem(Model.translate("about"));
        newSimulationButton = new JButton(new ImageIcon(getClass().getResource("icons/newSimulation.png")));
        newProjectButton = new JButton(new ImageIcon(getClass().getResource("icons/newProject.png")));
        openButton = new JButton(new ImageIcon(getClass().getResource("icons/openProject.png")));
        saveButton = new JButton(new ImageIcon(getClass().getResource("icons/save.png")));
//        saveAsButton = new JButton(new ImageIcon(getClass().getResource("icons/saveAs.png")));
        helpButton = new JButton(new ImageIcon(getClass().getResource("icons/help.png")));
        simulations = new Vector<SimulationPanel>();
        messages = new JLabel("SiFiSy - File System Simulator");

        // Creation of the menu items
        file.add(newSimulation);
        file.add(newProject);
        file.add(wizard);
        file.addSeparator();
        file.add(open);
        file.add(closeSimulation);
        file.add(closeProject);
        file.addSeparator();
        file.add(save);
//        file.add(saveAs);
        file.addSeparator();
        file.add(preferences);
        file.addSeparator();
        file.add(exit);
//        simulation.add(startSimulation);
//        project.add(parameters);
//        project.addSeparator();
//        project.add(startComparison);
        help.add(helpWizard);
        help.addSeparator();
        help.add(about);
        fileMenu.add(file);
//        fileMenu.add(simulation);
//        fileMenu.add(project);
        fileMenu.add(help);

        // Addition of Listeners
        exit.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                System.exit(0);
            }
        });
        about.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                new AboutWidget();
            }
        });
        newSimulation.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                new NewSimulationWidget();
            }
        });
        newSimulationButton.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                new NewSimulationWidget();
            }
        });
        newProject.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                new NewProjectWidget(MainWidget.this);
            }
        });
        newProjectButton.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                new NewProjectWidget(MainWidget.this);
            }
        });
        openButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                MainWidget.open();
            }
        });
        saveButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
//                int filter;
                JPanel panel;

                panel = (JPanel)getTabbedPane().getSelectedComponent();

                if (panel == null)
                    return;
                
                String filePath = "";

                if (panel instanceof SimulationPanel) {
                    SimulationPanel simPanel = (SimulationPanel)getTabbedPane().getSelectedComponent();
                    filePath = showSaveFileDialog(FILEFILTER_SIMULATION);
                    if (!filePath.equals(""))
                        Model.saveSimulation(simPanel.getSimulationId(), filePath, simPanel);
                }
                if (panel instanceof ProjectPanel) {
                    ProjectPanel prjPanel = (ProjectPanel)getTabbedPane().getSelectedComponent();
                    filePath = showSaveFileDialog(FILEFILTER_PROJECT);
                    if (!filePath.equals(""))
                        Model.saveProject(prjPanel.getProjectId(), filePath, prjPanel);
                }
            }
        });
        wizard.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                new WizardWidget().setVisible(true);
            }
        });
        open.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                MainWidget.open();
            }
        });
        save.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                String filePath = showSaveFileDialog(FILEFILTER_SIMULATION);

                if (!filePath.equals("")) {
                    SimulationPanel simPanel = (SimulationPanel)getTabbedPane().getSelectedComponent();
                    Model.saveSimulation(simPanel.getSimulationId(), filePath, simPanel);
                }
            }
        });
        preferences.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                new PreferencesWizard();
            }
        });
        helpWizard.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                (new HelpWizard()).setVisible(true);
            }
        });
        helpButton.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                (new HelpWizard()).setVisible(true);
            }
        });

        // Creating the treeView
        initTreeView();
        updateTreeView();
    }

    /**
     * Show an open file dialog for simulations and project
     * @return true if the simulation or project was opened successfully
     */
    public static boolean open() {
        String filePath = showOpenFileDialog(FILEFILTER_ALL);

        if (!filePath.equals("")) {
            if (filePath.indexOf(".sfs") != -1) {
                SimulationPanel panel = MainWidget.createSimulation("_sim_001");
                Model.openSimulation(filePath, panel);
                panel.refreshFields();

                return true;
            }
            if (filePath.indexOf(".fsp") != -1) {
                ProjectPanel panel = MainWidget.createProject("_prj_001");
                Model.openProject(filePath, panel);
                panel.refreshFields();

                return true;
            }
            JOptionPane.showMessageDialog(MainWidget.getMainWidgetFrame(),
                    "Tipo di file non riconosciuto",
                    "SiFiSy", JOptionPane.ERROR_MESSAGE);
            return false;
        }
        else
            return false;
    }

    /**
     * Create the tree view
     */
    private void initTreeView() {
        rootNode = new DefaultMutableTreeNode("ROOT");

        treeView.setBorder(new TitledBorder(Model.translate("treeViewDesc")));

        DefaultTreeModel treeModel = new DefaultTreeModel(rootNode);

        DefaultTreeCellRenderer cellRenderer = new DefaultTreeCellRenderer();
        cellRenderer.setOpenIcon(new ImageIcon(getClass().getResource("icons/small/project.png")));
        cellRenderer.setClosedIcon(new ImageIcon(getClass().getResource("icons/small/project.png")));
        cellRenderer.setLeafIcon(new ImageIcon(getClass().getResource("icons/small/simulation.png")));

        treeView.setRootVisible(false);
        treeView.setCellRenderer(cellRenderer);
        treeView.setModel(treeModel);

        treeView.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                if ((e.getClickCount() == 2) && (e.getButton() == MouseEvent.BUTTON1)) {
                    // double click with left mouse button
                    SifisyTreeNode selectedNode = (SifisyTreeNode)treeView.getLastSelectedPathComponent();

                    if (selectedNode == null) // nothing is selected
                        return;

                    if (selectedNode.getLevel() == 1) {
                        // top-level simulation or project node
                        tabbedPane.setSelectedIndex(selectedNode.getTabIndex());
                    }
                    if (selectedNode.getLevel() == 2) {
                        // simulation node owned by a project
                        // must select the project tab before
                        SifisyTreeNode parent = (SifisyTreeNode) selectedNode.getParent();
                        tabbedPane.setSelectedIndex(parent.getTabIndex());
                        // then select the simulation node
                        ((ProjectPanel) tabbedPane.getSelectedComponent()).getTabbedPane().setSelectedIndex(selectedNode.getTabIndex());
                    }
                }
            }
        });

        treeView.setPreferredSize(new Dimension(250, 0));
    }

    /**
     * Expand all the rows in the tree and update the UI
     */
    public static void updateTreeView() {
        for (int i=0; i<treeView.getRowCount(); i++) {
            treeView.expandRow(i);
        }

        treeView.updateUI();
    }

    /**
     * Return the index of node with the specified name
     * @param nodeName: the node to search
     * @return the index of the node; if the node is not found returns -1
     */
    private static int getNodeIndex(String nodeName) {
        int index = -1;
        for (int i=0; (i<rootNode.getChildCount()) && (index == -1); i++) {
            if (((SifisyTreeNode)rootNode.getChildAt(i)).getName().equals(nodeName)) {
                index = i;
            }
        }
        
        return index;
    }

    /**
     * Default constructor of MainWidget
     */
    public MainWidget() {
        super(Model.translate("mainTitle"));
        mainWidgetFrame = this;
        initComponents();
        //addNodeToTree("Default");

        JPanel statusBar = new JPanel(new FlowLayout(FlowLayout.RIGHT));
        statusBar.add(messages);

        JToolBar toolBar = new JToolBar();
        toolBar.setFloatable(false);
        toolBar.add(newSimulationButton);
        toolBar.add(newProjectButton);
        toolBar.add(openButton);
        toolBar.add(saveButton);
//        toolBar.add(saveAsButton);
        toolBar.add(helpButton);

        setLayout(new BorderLayout());
        setSize(1020,700);

        setJMenuBar(fileMenu);
        add(toolBar, BorderLayout.NORTH);
        //add(nowOpenManager, BorderLayout.WEST);
        add(treeView, BorderLayout.WEST);
        add(statusBar, BorderLayout.SOUTH);
        add(tabbedPane, BorderLayout.CENTER);
        setVisible(true);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        if (Model.getShowWizard().equals("true")) {
            WizardWidget wizardWidget = new WizardWidget();
            wizardWidget.setVisible(true);
        }
    }

    /**
     * Adds a node as a child of root node in the tree
     * @param node: the node to add
     */
    public static void addNodeToTree(SifisyTreeNode node) {
        addNodeToTree(node,
                (DefaultMutableTreeNode)getTreeView().getModel().getRoot());
        updateTreeView();
    }

    /**
     * Adds the node of as a child of parent node int the tree
     * @param node: the node to add
     * @param parentNode: the parent of the node to add
     */
    public static void addNodeToTree(SifisyTreeNode node,
            DefaultMutableTreeNode parentNode) {
        parentNode.add(node);
        updateTreeView();
    }

    /**
     * Remove the panel of a simulation from the tabbed pane
     * @param simPanel: the panel of the simulation to remove
     */
    public static void removeSimulation(SimulationPanel simPanel) {
        MainWidget.getTabbedPane().remove(simPanel);
    }

    /**
     * Remove a simulation from the list of opened simulations
     * @param name: the simulation to remove
     */
    public static void removeSimulationFromList(String name) {
        simulationsList.remove(name);

        int nodeIndex = getNodeIndex(name);
        if (nodeIndex != -1) {
            updateTreeView();
        }
        else {
        }
    }

    /**
     * Return the list of opened simulations
     * @return the list of opened simulations
     */
    public static Vector<String> getSimulationsList() {
        return simulationsList;
    }    

    /**
     * Remove a project from the list of opened projects
     * @param name: the project to remove
     */
    public static void removeProjectFromList(String name) {
        projectsList.remove(name);

        int nodeIndex = getNodeIndex(name);
        if (nodeIndex != -1) {
            updateTreeView();
        }
        else {
        }
    }

    /**
     * Return the list of opened projects
     * @return the list of opened projects
     */
    public static Vector<String> getProjectsList() {
        return projectsList;
    }

    /**
     * Show an open file dialog for simulations and projects
     * @return the full path of the file to open
     */
    public static String showOpenFileDialog(int fileFilter) {
        JFileChooser fileChooser = new JFileChooser();

        fileChooser.setAcceptAllFileFilterUsed(false);
        FileNameExtensionFilter sfsFileFilter = new FileNameExtensionFilter(Model.translate("sfsFileFilter"), "sfs");
        FileNameExtensionFilter fspFileFilter = new FileNameExtensionFilter(Model.translate("fspFileFilter"), "fsp");
        FileNameExtensionFilter allFileFilter = new FileNameExtensionFilter(Model.translate("allFileFilter"), "sfs", "fsp");

        switch (fileFilter) {
            case (FILEFILTER_ALL): {
                fileChooser.addChoosableFileFilter(sfsFileFilter);
                fileChooser.addChoosableFileFilter(fspFileFilter);
                fileChooser.addChoosableFileFilter(allFileFilter);
                break;
            }
            case (FILEFILTER_SIMULATION): {
                fileChooser.addChoosableFileFilter(sfsFileFilter);
                break;
            }
            case (FILEFILTER_PROJECT): {
                fileChooser.addChoosableFileFilter(fspFileFilter);
                break;
            }
        }

        int dlgResult = fileChooser.showOpenDialog(MainWidget.getMainWidgetFrame());
        String filePath = "";

        switch (dlgResult) {
            case (JFileChooser.APPROVE_OPTION): {
                filePath = fileChooser.getSelectedFile().getPath();
                break;
            }
            case (JFileChooser.CANCEL_OPTION): {
                break;
            }
            case (JFileChooser.ERROR_OPTION): {
                break;
            }
        }

        return filePath;
    }

    /**
     * Show a save file dialog with the specified file filter
     * @param fileFilter: the file filter can be MainWidget.FILEFILTER_SIMULATION,
     * MainWidget.FILEFILTER_PROJECT, MainWidget.FILEFILTER_PNG or
     * MainWidget.FILEFILTER_PDF
     * @return the full path of the file to save
     */
    public static String showSaveFileDialog(int fileFilter) {
        JFileChooser fileChooser = new JFileChooser();
        String description = "";
        String extension = "";

        fileChooser.setAcceptAllFileFilterUsed(false);
        switch (fileFilter) {
            case (FILEFILTER_PDF): {
                description = "Adobe pdf";
                extension = "pdf";
                break;
            }
            case (FILEFILTER_PNG): {
                description = "Immagine png";
                extension = "png";
                break;
            }
            case (FILEFILTER_SIMULATION): {
                description = Model.translate("sfsFileFilter");
                extension = "sfs";
                break;
            }
            case (FILEFILTER_PROJECT): {
                description = Model.translate("fspFileFilter");
                extension = "fsp";
                break;
            }
        }

        fileChooser.addChoosableFileFilter(new FileNameExtensionFilter(description, extension));

        int dlgResult = fileChooser.showSaveDialog(MainWidget.getMainWidgetFrame());
        String filePath = "";

        switch (dlgResult) {
            case (JFileChooser.APPROVE_OPTION): {
                filePath = fileChooser.getSelectedFile().getPath();
                if (filePath.indexOf("." + extension) == -1)
                    filePath += "." + extension;
                break;
            }
            case (JFileChooser.CANCEL_OPTION): {
                break;
            }
            case (JFileChooser.ERROR_OPTION): {
                break;
            }
        }

        return filePath;
    }

    /**
     * Create a new simulation with the specified name and adds it to the tabbed
     * pane
     * @param simulationName: the name of the simulation
     * @return the SimulationPanel created
     */
    public static SimulationPanel createSimulation(String simulationName) {
        SifisyTreeNode node = new SifisyTreeNode(simulationName);
        SimulationPanel simPanel = new SimulationPanel(simulationName, node);
        addNodeToTree(node);
        getTabbedPane().addTab(simulationName,
                new ImageIcon(MainWidget.getMainWidgetFrame().getClass().getResource("icons/small/simulation.png")),
                simPanel);
        getTabbedPane().setSelectedIndex(MainWidget.getTabbedPane().getTabCount() - 1);
        node.setTabIndex(MainWidget.getTabbedPane().getSelectedIndex());
        simulationsList.add(simulationName);

        return simPanel;
    }

    /**
     * Create a new simulation into a project with the specified name and add
     * it to the tabbed pane of the project
     * @param simulationName: the name of the simulation
     * @param panel: the parent ProjectPanel
     * @return the SimulationPanel created
     */
    public static SimulationPanel createSimulation(String simulationName,
            ProjectPanel panel) {
        SifisyTreeNode node = new SifisyTreeNode(simulationName);
        SimulationPanel simPanel = panel.addSimulation(simulationName, node);
        node.setTabIndex(panel.getTabbedPane().getSelectedIndex());
        simulationsList.add(simulationName);

        return simPanel;
    }

    /**
     * Create a project with the specified name and add it to the tabbed pane
     * @param projectName: the name of the project
     * @return the ProjectPanel created
     */
    public static ProjectPanel createProject(String projectName) {
        SifisyTreeNode node = new SifisyTreeNode(projectName);
        ProjectPanel prjPanel = new ProjectPanel(projectName, node);
        addNodeToTree(node);
        MainWidget.getTabbedPane().addTab(projectName,
                new ImageIcon(prjPanel.getClass().getResource("icons/small/project.png")),
                prjPanel);
        getTabbedPane().setSelectedIndex(MainWidget.getTabbedPane().getTabCount() - 1);
        node.setTabIndex(MainWidget.getTabbedPane().getSelectedIndex());
        projectsList.add(projectName);

        return prjPanel;
    }

    public static void main(String[] args) {
        Model.loadSetup();
        MainWidget mainWidget = new MainWidget();
    }
}
